﻿using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Reflection.Emit;
using System.Text;
using System.Threading.Tasks;
using System.Xml;
using Microsoft.Build.Evaluation;
using RazorEngine;
using RazorEngine.Templating;
using Encoding = System.Text.Encoding;

namespace CodeBuilder.Code
{
    public class BuildHelper
    {
        private string _viewsPath;
        private string _csprojPath;
        private string _controllerPath;
        private string _modelsPath;
        private string _connStr;
        private string _controller;
        private string _tableName;
        private Project _project;

        public BuildHelper(string connStr, string slnPath, string controller, string tableName)
        {
            if (!File.Exists(slnPath))
            {
                throw new Exception("找不到sln文件");
            }
            _connStr = connStr;
            _tableName = tableName;
            _controller = controller;
            //获取运营后台的路径
            var codePath = Path.GetDirectoryName(slnPath);
            _csprojPath = Path.Combine(codePath, "QD.Web.Management", "QD.Web.Management.csproj");
            _viewsPath = Path.Combine(codePath, "QD.Web.Management", "Views");
            _modelsPath = Path.Combine(codePath, "QD.Web.Management", "Models");
            _controllerPath = Path.Combine(codePath, "QD.Web.Management", "Controllers");
            _controllerPath = Path.Combine(_controllerPath, controller + "Controller.cs");

            _project = new Project(_csprojPath);
        }
        public void Process()
        {
            //新建controller文件并加到csproj中
            ProcessController();
            //在views下新建文件夹和文件并加到csproj中
            ProcessViews();
            //在model下新建两个类并加到csproj中
            ProcessModels();
        }

        private void ProcessModels()
        {
            //在model下新建三个类并加到csproj中
            var path = Path.Combine(_modelsPath, _controller);
            if (!Directory.Exists(path)) //创建文件夹
            {
                Directory.CreateDirectory(path);
            }
            var columns = new SqlStructure(_connStr).GetColumns(_tableName).ToList();
            ProcessModel("ParamModel", _tableName + "Param",  columns);
            ProcessModel("DomainModel", _tableName + "_Domain", columns);
            ProcessModel("ExportModel", _tableName + "ExportModel", columns);
        }
        private void ProcessController()
        {
            //新建controller文件并加到csproj中
            var columns = new SqlStructure(_connStr).GetColumns(_tableName).ToList();
            var template = GetTemplate("Controller.tpl");
            var model =
                new
                {
                    ControllerName = _controller,
                    DomainModelName = _tableName + "_Domain",
                    ParamName = _tableName + "Param",
                    Columns = columns,
                    ExportModel = _tableName + "ExportModel",
                    TableName = _tableName,
                };
            var result = Engine.Razor.RunCompile(template, "Controller.tpl", null, model);
            var path = _controllerPath;
            SaveFile(result, path);
            UpdateCsproj("Controllers\\" + _controller + "Controller.cs");

        }
        private void ProcessViews()
        {
            //在views下新建文件夹和文件并加到csproj中
            var path = Path.Combine(_viewsPath, _controller);
            if (!Directory.Exists(path)) //创建文件夹
            {
                Directory.CreateDirectory(path);
            }
            var columns = new SqlStructure(_connStr).GetColumns(_tableName).ToList();
            ProcessView("Index_Partial",  columns);
            ProcessView("Index",  columns);
        }
        //处理单个Model
        private void ProcessModel(string tpl, string newName,  List<ColumnInfo> columns)
        {
            var template = GetTemplate(tpl + ".tpl");
            var model =
                new
                {
                    ControllerName = _controller,
                    DomainModelName = _tableName + "_Domain",
                    ParamName = _tableName + "Param",
                    ExportName = _tableName + "ExportModel",
                    Columns = columns
                };
            var result = Engine.Razor.RunCompile(template, tpl + ".tpl", null, model);
            var path = Path.Combine(_modelsPath, _controller, newName + ".cs");
            SaveFile(result, path);
            UpdateCsproj("Models\\" + _controller + "\\" + newName + ".cs");
        }
        //处理单个view
        private void ProcessView(string tpl,  List<ColumnInfo> columns)
        {
            var template = GetTemplate(tpl + ".tpl");
            var model =
                new
                {
                    ControllerName = _controller,
                    DomainModelName = _tableName + "_Domain",
                    ParamName = _tableName + "Param",
                    Columns = columns
                };
            var result = Engine.Razor.RunCompile(template, tpl + ".tpl", null, model);
            var path = Path.Combine(_viewsPath,_controller, tpl + ".cshtml");
            SaveFile(result, path);
            UpdateCsproj("Views\\" + _controller + "\\" + tpl + ".cshtml");
        }


        private string GetTemplate(string filename)
        {
            var path = Path.Combine(System.AppDomain.CurrentDomain.BaseDirectory, "Template", filename);
            var fs = new FileStream(path, FileMode.Open, FileAccess.Read);
            return Stream2String(fs, System.Text.Encoding.UTF8);
        }

        private string Stream2String(Stream stream, System.Text.Encoding encoding)
        {
            using (var sr = new StreamReader(stream, encoding))
            {
                return sr.ReadToEnd();
            }
        }

        private byte[] StringToBytes(string str)
        {
            var temp = System.Text.Encoding.UTF8.GetBytes(str);
            return temp;
        }

        private void SaveFile(string str, string path)
        {
            var fs = new FileStream(path, FileMode.OpenOrCreate, FileAccess.ReadWrite);
            var bytes = StringToBytes(str);
            fs.Write(bytes, 0, bytes.Length);
        }

        private void UpdateCsproj(string includePath)
        {
            if (includePath.EndsWith(".cshtml"))
            {
                _project.AddItem("Content", includePath);
            }
            else if (includePath.EndsWith(".cs"))
            {
                _project.AddItem("Compile", includePath);
            }
            _project.Save();
        }
    }
}
